#include "number.hpp"
#include "calcwhole.hpp"

实数::实数(){}

实数::实数(const string& n){
    符号=1;
    if(n.empty()){分子.resize(1,0),分母.resize(1,1);return;}
    auto begin=n.begin(),end=n.end();
    size_t minus=0;
    if(*begin=='-')符号=-1,begin++,minus=1;
    if(begin==end){
        分子.resize(1,0);
        分母.resize(1,1);
        符号=1;
        return;
    }
    //一遍找小数点位置并验证格式
    auto point=end;
    分子.resize(n.size()-minus);
    auto set=分子.rbegin();
    while(begin!=end){
        auto c=*begin;
        if('0'<=c&&c<='9'){
            *set++=*begin++-'0';
            continue;
        }
        if(c=='.'&&point==end){
            point=++begin;
            continue;
        }
        if(c=='.'&&point!=end)throw 小数格式错误();
        throw 不是一个十进制数();
    }
    if(point!=end)copy(分子.begin()+1,分子.end(),分子.begin()),分子.pop_back();
    分母.resize(end-point+1,0);
    *分母.rbegin()=1;
}

string 实数::小数形式(size_t n){
    size_t minus=0;
    if(符号==-1)minus=1;
    string whole,small;
    运算::整数::除(分子,分母,whole,small,n+1);
    if(small.front()>=5){
        for(auto begin=small.begin()+1,end=small.end();begin!=end;begin++){
            if(++*begin==10){
                *begin=0;
                continue;
            }
            break;
        }
    }
    string temp(whole.size()+small.size()+2+minus,0);
    auto set=temp.begin();
    if(minus)*set++='-';
    for(auto begin=whole.rbegin(),end=whole.rend();begin!=end;begin++,set++){
        *set=*begin+'0';
    }
    *set++='.';
    for(auto begin=small.rbegin(),end=small.rend()-1;begin!=end;begin++,set++){
        *set=*begin+'0';
    }

    return temp;
}

string 实数::分数形式(){
    size_t minus=0;
    if(符号==-1)minus=1;
    string temp(分子.size()+分母.size()+2+minus,0);
    auto set=temp.begin();
    if(minus)*set++='-';
    for(auto begin=分子.rbegin(),end=分子.rend();begin!=end;begin++,set++){
        *set=*begin+'0';
    }
    *set++='/';
    for(auto begin=分母.rbegin(),end=分母.rend();begin!=end;begin++,set++){
        *set=*begin+'0';
    }
    return temp;
}

string 实数::整数形式(){
    string result,remain;
    运算::整数::整除(分子,分母,result,remain);
    return result;
}

实数 实数::同加(const 实数& n){
    实数 temp;
    if(分母==n.分母){
        运算::整数::加(分子,n.分子,temp.分子);
        temp.符号=符号,temp.分母=分母;
        return temp;
    }
    string a,b;
    运算::整数::乘(分母,n.分母,temp.分母);
    运算::整数::乘(分子,n.分母,a);
    运算::整数::乘(n.分子,分母,b);
    运算::整数::加(a,b,temp.分子);
    temp.符号=符号;
    return temp;
}

实数 实数::同减(const 实数& n){
    实数 temp;
    if(分母==n.分母){
        temp.符号=运算::整数::减(分子,n.分子,temp.分子);
        temp.分母=分母;
        return temp;
    }
    string a,b;
    运算::整数::乘(分母,n.分母,temp.分母);
    运算::整数::乘(分子,n.分母,a);
    运算::整数::乘(n.分子,分母,b);
    temp.符号=运算::整数::减(a,b,temp.分子);
    return temp;
}

实数 实数::负加(const 实数& n){
    实数 temp;
    if(分母==n.分母){
        temp.符号=运算::整数::减(n.分子,分子,temp.分子);
        temp.分母=分母;
        return temp;
    }
    string a,b;
    运算::整数::乘(分母,n.分母,temp.分母);
    运算::整数::乘(分子,n.分母,a);
    运算::整数::乘(n.分子,分母,b);
    temp.符号=运算::整数::减(b,a,temp.分子);
    return temp;
}

实数 实数::operator+(const 实数& n){
    if(符号==n.符号)return 同加(n);
    if(n.符号==-1)return 同减(n);
    return 负加(n);
}

实数 实数::operator-(const 实数& n){
    if(符号==n.符号)return 同减(n);
    if(符号==-1)return 负加(n);//- +
    return 同加(n);//+ -
}

实数 实数::operator*(const 实数& n){
    实数 temp;
    运算::整数::乘(分子,n.分子,temp.分子);
    运算::整数::乘(分母,n.分母,temp.分母);
    if(符号==n.符号){
        temp.符号=1;
        return temp;
    }
    temp.符号=-1;
    return temp;
}

实数 实数::operator/(const 实数& n){//a/b->a/1*1/b
    实数 temp;
    运算::整数::乘(分子,n.分母,temp.分子);
    运算::整数::乘(分母,n.分子,temp.分母);
    if(符号==n.符号){
        temp.符号=1;
        return temp;
    }
    temp.符号=-1;
    return temp;
}

bool 实数::operator>(const 实数& 数){return 比较(数)==1;}
bool 实数::operator>=(const 实数& 数){return 比较(数)>=0;}
bool 实数::operator<(const 实数& 数){return 比较(数)<0;}
bool 实数::operator<=(const 实数& 数){return 比较(数)<=0;}
bool 实数::operator==(const 实数& 数){return !比较(数);}
bool 实数::operator!=(const 实数& 数){return 比较(数);}

void 实数::整除(const 实数& n,实数& result,实数& remain){
    string a;
    运算::整数::乘(分子,n.分母,a);
    运算::整数::乘(分母,n.分子,result.分母);
    运算::整数::乘(分母,n.分母,remain.分母);
    auto sign=符号==n.符号?1:-1;
    remain.符号=sign;
    result.符号=sign;
    运算::整数::整除(a,result.分母,result.分子,remain.分子);
    result.分母=remain.分母;
}

int 实数::比较(const 实数& n){
    if(符号>n.符号)return 1;
    if(符号<n.符号)return -1;
    //同号
    if(分母==n.分母)return 运算::整数::比较(分子,n.分子);
    if(分子==n.分子)return 运算::整数::比较(n.分母,分母);
    string a,b,c;
    //通分
    运算::整数::乘(分子,n.分母,a);
    运算::整数::乘(n.分子,分母,b);
    auto ret=运算::整数::减(a,b,c);
    if(!c.back())return 0;
    if(ret<0)return -1;
    return 1;
}